home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 10
/
The PC-Sig Library - Shareware for the IBM PC and Compatibles (PC-SIG)(Tenth Edition Disks 1-2804)(1991).iso
/
PC_SIGCD
/
05
/
6
/
DISK0564.ZIP
/
SOURCE.ARC
/
LS.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-04-02
|
40KB
|
1,125 lines
TITLE LS - SORTED DIRECTORY PROGRAM
PAGE 55,132
;************************************************************************
; THIS PROGRAM DISPLAYS A SORTED DIRECTORY WITH FILE SIZES.
; IT REQUIRES MSDOS VERSION 2 OR HIGHER.
;
; usage: LS [-A -D -L -N -R -S - T -1] afn
; -A includes hidden and system files
; -D displays information on directory (not its contents)
; -L shows date, time, file size in bytes for each file
; -N suppresses sorting
; -R reverses order of sort
; -T sorts by date/time of file
; -S shows file sizes
; -1 forces single-column display with no paging
; afn may contain * and ?: e.g. "LS PROG?.*"
;
; BY: JON DART
; 3012 HAWTHORN ST.,
; SAN DIEGO, CA 92104
;
; Version 3.2, 30-Mar-89 -T option without -R sorts dates so that most
; recent files are first (like unix). Illegal
; switch error msg. also corrected.
; Version 3.1, 21-Mar-89 fixed bug in free space display.
; Version 3.0, 18-Jan-89 modifications to handle disks > 65 Megabytes.
; also a bug fix in FIXPATH.
; Version 2.2, 30-Apr-88 allows multiple file arguments, uses GETARGS
; library routine, adds NODUPES procedure.
; Version 2.1, 09-Feb-88 minor cleanup, some redundant code removed.
; Version 2.0, 28-Nov-87 fixes bug in display of very large directories.
; -S and -D options and PAD asssembly option added. Old
; -D option changed to -T.
; Version 1.9, 01-Nov-87 assembles under MASM 5.0
; Version 1.8, 24-Oct-86 adds LOWCASE assembly option, -1, -D, -N and
; -R switches. Some problems in redirecting output to
; disk were fixed. Also minor bugs in display routine.
; Version 1.7, 04-Oct-86 linked with new library, no longer writes
; nulls to console (which interfered with screen print)
; Version 1.6, 05-Jul-86 fixes sometime loss of top display line.
; Now accepts - as well as / for switches.
; Also modified to assemble under MASM 4.0.
; Version 1.5, 04-May-86 fixes clear screen routine
; Version 1.4, 17-Jan-86 UTIL and CONSOLE made external modules,
; adds FIXPATH function
; Version 1,3, 07-Nov-85 /L option added
; Version 1.2, 03-Nov-85 fixes bug in size function
; Version 1.1, 18-Oct-85
;
; TO BUILD LS.EXE:
; MASM LS,LS,NUL,NUL
; LINK LS,LS,NUL,ASM
; EXEPACK LS.EXE LS.NEW
; DEL LS.EXE
; REN LS.NEW LS.EXE
TRUE EQU 1
FALSE EQU 0
IBM EQU TRUE ;TRUE IF IBM-COMPATIBLE AT BIOS LEVEL
LOWCASE EQU FALSE ;TRUE FOR LOWER-CASE OUTPUT (FOR UNIX PURISTS)
PAD EQU TRUE ;PAD FILE NAMES WITH SPACES (SO EXTENSIONS LINE
;UP). FALSE MEANS DON'T PAD WITHIN FILE NAMES.
BIOS EQU 10H ;BIOS INTERRUPT FOR VIDEO FUNCTIONS
MAXARGS EQU 100 ;MAX # COMMAND-LINE ARGUMENTS
MAXFILES EQU 512 ;MAX # OF FILES
NCOLUMN EQU 5 ;# OF COLUMNS TO DISPLAY (SHORT MODE,
;WITH NO FILE SIZES)
NCOLUMNS EQU 4 ;# OF COLUMNS TO DISPLAY (SHORT MODE,
;WITH FILE SIZES)
MAXLINES EQU 24 ;# LINES ON SCREEN FOR FILE DISPLAY
IF IBM
FENCE EQU 179 ;VERTICAL BAR CHAR. (IBM ONLY)
ELSE
FENCE EQU '|' ;BORDER BETWEEN COLUMNS
ENDIF
K EQU 1024 ;1 K
M EQU BYTE PTR 0[BX]
.XLIST
INCLUDE ASCII.DEF
INCLUDE MSDOS2.DEF
INCLUDE MACROS.DEF
.LIST
ERROR MACRO ERRNUM ;SHOW ERROR MESSAGE
MOV DX,OFFSET MSG&ERRNUM
CALL ERRORMSG
ENDM
; UNINITIALIZED DATA
DATA SEGMENT PUBLIC PARA 'DATA'
DGROUP GROUP DATA
ASSUME DS:DGROUP
ARGPTRS DW MAXARGS DUP (?) ;POINTERS TO START OF ARGUMENTS
ARGBUF DB 256 DUP (?) ;BUFFER FOR ARGUMENTS
FILNAM DB 80 DUP (?) ;FILE NAME FROM COMMAND LINE
SPATH DB 80 DUP (?) ;SEARCH PATH
SPREFIX DB 80 DUP (?) ;SEARCH PREFIX (NOT USED)
OUR_DTA DB 128 DUP (?) ;DISK TRANSFER ADDRESS, USED BY MSDOS
;FUNCTIONS 4EH AND 4FH.
ADDRLIST DB (2*MAXFILES) DUP (?) ;HOLDS POINTERS TO INFO ON EACH FILE
BUFFER DB (22*MAXFILES) DUP (?) ;HOLDS INFO ON EACH FILE, RETURNED BY
;MSDOS FUNCTION 4EH OR 4FH.
ENDBUF EQU BUFFER+(MAXFILES*22)
STACK SEGMENT PARA STACK 'STACK'
ASSUME SS:STACK
DB 512 DUP (?)
STACK ENDS
;*********************
; MEMORY DEFINITIONS *
;*********************
;
SWLIST DB 'ADLNRST1',0 ;LIST OF LEGAL SWITCHES
AFLAG DW 0 ;SET <>0 IF -A
DFLAG DW 0 ;SET <>0 IF -D
LFLAG DW 0 ;SET <>0 IF -L
NFLAG DW 0 ;SET <>0 IF -N
RFLAG DW 0 ;SET <>0 IF -R
SFLAG DW 0 ;SET <>0 IF -S
TFLAG DW 0 ;SET <>0 IF -T
ONEFLAG DW 0 ;SET <>0 IF -1
DRIVE DB 0 ;DRIVE (0 FOR DEFAULT, 1 FOR A, ETC)
ISDEV DB 0 ;=0 IF OUTPUT REDIRECTED TO DISK
VPAGE DB 0 ;VIDEO PAGE # (IBM ONLY)
SCRSIZE DB 80 ;SCREEN WIDTH (80 IS DEFAULT FOR NON-IBM)
VMODE DB 0 ;DISPLAY MODE (IBM ONLY)
ATTRIBUTES DB 00010001B ;DEFAULT FILE ATTRIBUTES
NUMFILES DW 0 ;NUMBER OF FILES FOUND
NDUPES DW 0 ;NUMBER OF DUPLICATE FILE NAMES
GAP DW 0 ;USED BY SORT ROUTINE
COLCOUNT DW 1 ;COUNT OF COLUMNS DISPLAYED
LINECOUNT DW 1 ;COUNT OF LINES DISPLAYED
FIRSTSCREEN DW 1 DUP (?) ;SET =1 IF -L OR -S AND FIRST SCREEN
FILECOUNT DW 0 ;COUNT OF FILES DISPLAYED
BASE DW 1 ;FIRST FILE TO SHOW
NEXTFREE DW 1 DUP (?) ;ADDR. OF NEXT FREE SLOT IN BUFFER
MAXLINE DW 1 DUP (?) ;NO. OF LINES TO DISPLAY
MAXFILE DW 1 DUP (?) ;MAX FILE TO SHOW
MAXCOL DB 1 DUP (?) ;COLUMN WIDTH OF DISPLAY
FILESPERSCREEN DW 1 DUP (?) ;FILES PER SCREEN
LOSIZE DW 1 DUP (?) ;USED IN CALCULATING FREE SPACE
USED DQ 0 ;COUNT OF FILE SPACE USED
DEFAULT DB '????????.???',0 ;DEFAULT FILE NAME
TXT0 DB '<DIR','>',0 ;SAY IT'S A DIR
TXT1 DB ' files, using ',0
TXT2 DB ' bytes ','(',0
TXT3 DB ' bytes free',')',0
TXT4 DB ' free',')',0
TXT5 DB CR,LF,0
MSG2 DB ' : no matching files.',CR,LF,0
MSG3 DB '[ More ] ',0
MSG4 DB CR,LF,'illegal switch: ',0
MSG5 DB CR,LF,'too many arguments',CR,LF,0
DATA ENDS
CODE SEGMENT PUBLIC PARA 'CODE'
ASSUME CS:CODE
EXTRN SKIPSP:NEAR,UC:NEAR,DECOUT:NEAR,CPYCNT:NEAR,CPY:NEAR
EXTRN UCSTR:NEAR
EXTRN CMDSRC:NEAR
EXTRN ERRORMSG:NEAR
EXTRN TYPTX:NEAR
EXTRN PRTSTR:NEAR
EXTRN PRINTDD:NEAR
EXTRN COUT:NEAR,CIN:NEAR,CLRCO:NEAR,CRLF:NEAR
EXTRN FIXPATH:NEAR
EXTRN TYPE_DIR:ABS
EXTRN GETARGS:NEAR
;*********************
; START OF CODE HERE *
;*********************
ENTRY:
TEST_DOS2 ;TEST FOR DOS 2.0, EXIT IF DOS 1
PUSH DS
MOV AX,DGROUP
MOV DS,AX
MOV AL,0 ;PREPARE TO CHECK DEVICE STATUS
MOV BX,1 ;OF STDOUT
MOV AH,IO_CTL
INT DOS ;GET STATUS
AND DX,0080H ;MASK ISDEV BIT
MOV BYTE PTR ISDEV,DL ;SAVE RESULT
IF IBM
MOV AH,15
INT BIOS ;GET VIDEO MODE
MOV BYTE PTR VPAGE,BH ;STORE VIDEO PAGE #
MOV BYTE PTR SCRSIZE,AH ;STORE CHARS/LINE
MOV BYTE PTR VMODE,AL ;STORE DISPLAY MODE
ENDIF
POP DS
CALL PARSE_SWITCHES ;PARSE COMMAND-LINE SWITCHES
MOV AX,OFFSET BUFFER
MOV WORD PTR NEXTFREE,AX ;INIT "NEXTFREE" TO START OF FILE LIST
GETFILES:
PUSH CX
PUSH SI
CALL PARSE_ARG ;BUILD SEARCH PATH
CALL FIND_FILES ;SEARCH FOR FILES, BUILD LIST IN MEMORY
POP SI
POP CX
ADD SI,2
CMP CX,0
JLE SORT
LOOP GETFILES
SORT:
CALL SORT_FILES ;SORT FILE LIST
CALL SHOW_INFO ;SHOW DISK USAGE INFO
CALL SHOW_FILES ;DISPLAY DIRECTORY
MOV AX,256*EXIT
INT DOS ;EXIT TO DOS
;***********************************************
; PARSE COMMAND LINE SWITCHES *
; ENTRY: DS:BX POINTS TO DOS COMMAND LINE *
; RETURNS: CX = # OF ARGUMENTS (LESS SWITCHES) *
; SI = POINTER TO ARGUMENT POINTERS *
;***********************************************
PARSE_SWITCHES PROC NEAR
MOV AX,DGROUP
MOV ES,AX
MOV BX,(80H) ;GET BYTE COUNT FOR COMMAND LINE
PUSH BX
MOV DL,[BX]
MOV DH,0
ADD BX,DX
INC BX
MOV [BX],BYTE PTR 0 ;PUT 0 BYTE AT END OF COMMAND LINE
POP BX
INC BX
MOV SI,OFFSET ARGPTRS
MOV DI,OFFSET ARGBUF
MOV CX,MAXARGS
CALL GETARGS ;COLLECT COMMAND LINE ARGUMENTS
JNB L_2 ;IF OK
TOOMANY:
ERROR 5 ;TOO MANY ARGUMENTS (PRETTY UNLIKELY)
MOV AL,5 ;SET EXIT CODE
MOV AH,EXIT
INT DOS ;EXIT TO DOS
;***************************
; COLLECT SWITCHES, IF ANY *
;***************************
L_2:
MOV AX,DGROUP
MOV DS,AX ;POINT TO OUR DATA SEG, NOT PSP
MOV SI,OFFSET ARGPTRS
NEXTSW:
MOV BX,WORD PTR [SI] ;POINT TO ARGUMENT
MOV AL,BYTE PTR [BX] ;GET 1ST CHAR.
CMP AL,'-'
JE GOTSW ;IF SWITCH SPECIFIED
CMP AL,'/'
JE GOTSW
RET
GOTSW:
INC BX ;SKIP OVER SWITCH CHARACTER
MOV AL,BYTE PTR [BX]
SWLOOP:
CALL UC ;MAKE SWITCH UPPER CASE
PUSH BX
MOV BX,OFFSET SWLIST
CALL CMDSRC ;SEARCH LIST OF VALID SWITCHES
POP BX
MOV AH,0
ADD AX,AX ;NOT FOUND IN LIST?
JZ BADSWITCH ;NO.
MOV DI,OFFSET AFLAG - 2
ADD DI,AX ;POINT TO FLAG
NOT WORD PTR [DI] ;1'S COMPLEMENT
INC BX
MOV AL,BYTE PTR [BX] ;GET NEXT CHAR. FROM LINE
COMPLIST <SPACE,TAB,NULL>,ENDSW ;IF DELIM
JMP SWLOOP ;ELSE ASSUME THIS IS A SWITCH CHAR.
ENDSW: ADD SI,2 ;POINT TO NEXT POINTER TO AN ARG
LOOP NEXTSW
RET ;NO ARGS BESIDES SWITCHES
BADSWITCH:
ERROR 4 ;ILLEGAL SWITCH
MOV AL,BYTE PTR [BX]
CALL COUT ;DISPLAY BAD CHAR.
CALL CRLF
MOV AL,4 ;SET EXIT CODE
MOV AH,EXIT
INT DOS ;EXIT TO DOS
PARSE_SWITCHES ENDP
;*****************************************************************
; TAKE A COMMAND LINE ARGUMENT AND SET UP SEARCH PATH IN "SPATH" *
;*****************************************************************
PARSE_ARG PROC NEAR
CMP CX,0
JE NONAME ;IF NULL ARGUMENT
MOV BX,[SI]
MOV AL,BYTE PTR [BX+1]
CMP AL,':' ;SEE IF DRIVE SPECIFIED
JNE NODRIVE ;IF NOT
MOV AL,BYTE PTR [BX] ;GET DRIVE LETTER
CALL UC ;MAKE UPPER-CASE
MOV BYTE PTR FILNAM,AL ;SAVE DRIVE LETTER IN FILE NAME BUFFER
MOV BYTE PTR (FILNAM+1),':' ;SAVE COLON ALSO
SUB AL,'A'-1 ;CONVERT ASCII TO BINARY (A=1, ETC.)
MOV BYTE PTR DRIVE,AL ;SAVE BINARY DRIVE
ADD BX,2 ;SKIP OVER DRIVE AND COLON
CALL SKIPSP ;ANYTHING AFTER DRIVE SPEC?
MOV SI,BX ;SAVE START OF FILE NAME, JUST IN CASE
JNB DRVPLUSFILE ;IF FILE NAME GIVEN, COPY INTO NAME BUFFER
MOV SI,OFFSET DEFAULT ;ELSE SI POINTS TO DEFAULT FILE NAME
DRVPLUSFILE:
MOV DI,OFFSET FILNAM+2 ;DI POINTS TO DESTINATION
JMP SHORT COPYNAME2 ;GO COPY FILENAME TO FILE BUFFER
NONAME:
MOV SI,OFFSET DEFAULT ;IF NO NAME, JUST COPY DEFAULT TO FILNAM
MOV DI,OFFSET FILNAM
JMP SHORT COPYNAME2
NODRIVE:
COPYNAME:
MOV SI,BX ;DS:SI POINTS TO START OF NAME
MOV DI,OFFSET FILNAM
COPYNAME2:
MOV CX,80
CALL CPYCNT ;SAVE FILE NAME
MOV BX,OFFSET FILNAM ;BX - FILE NAME
MOV CX,OFFSET SPATH ;CX - STORAGE FOR SEARCH PATH
MOV DX,OFFSET SPREFIX ;DX - STORAGE FOR SEARCH PREFIX (NOT USED)
CALL FIXPATH ;PARSE FILE NAME
CMP AX,TYPE_DIR
JE GOTDIR ;IF DIRECTORY
RET
GOTDIR: CMP BYTE PTR DFLAG,0 ;-D FLAG SET?
JNE DFLAGSET
RET
DFLAGSET:
MOV SI,OFFSET FILNAM
MOV DI,OFFSET SPATH
MOV CX,65
CALL CPYCNT ;MAKE SEARCH PATH = FILE NAME
RET
PARSE_ARG ENDP
;**********************
; FILE SEARCH ROUTINE *
;**********************
FIND_FILES PROC NEAR
MOV DX,OFFSET OUR_DTA ;LOAD DTA OFFSET
MOV AH,SET_DTA
INT DOS ;SET UP DTA
MOV CX,WORD PTR ATTRIBUTES ;GET DEFAULT ATTRIBUTES
CMP BYTE PTR AFLAG,0 ;A FLAG SET?
JE SHORT NOAFLAG ;NO
OR CX,00000110B ;YES, SET SYSTEM & HIDDEN ATTRIBUTES
NOAFLAG:
;***********************
; SEARCH FOR 1ST MATCH *
;***********************
MOV DX,OFFSET SPATH ;POINT TO SEARCH PATH
MOV AH,FIND_FIRST
INT DOS ;SEARCH FOR 1ST MATCH
JNC FOUND1ST ;IF FOUND
MOV DX,OFFSET TXT5
CALL ERRORMSG
MOV DX,OFFSET FILNAM ;POINT TO FILE NAME
CALL ERRORMSG
ERROR 2 ;NO MATCHING FILES
MOV AX,256*EXIT+2
INT DOS
;*********************************************************************
; COLLECT FILE INFO BLOCKS IN BUFFER, POINTERS TO BLOCKS IN ADDRLIST *
;*********************************************************************
FOUND1ST:
FOUND1: INC WORD PTR NUMFILES
CMP WORD PTR NUMFILES,MAXFILES
JGE LASTFILE
MOV DI,WORD PTR NEXTFREE
PUSH DI
MOV SI,OFFSET OUR_DTA+21
MOV CX,22
CALL CPY ;COPY FILE INFO TO TABLE
MOV AX,WORD PTR OUR_DTA+26 ;LSW OF FILE SIZE
MOV DX,WORD PTR OUR_DTA+28 ;MSW OF FILE SIZE
ADD AX,WORD PTR USED ;ADD LSW OF FILE SIZE TO
;LSW OF USED COUNT
MOV WORD PTR USED,AX
ADC WORD PTR USED+2,DX ;NOW ADD MSW
ADD WORD PTR NEXTFREE,22
MOV AX,NUMFILES
ADD AX,AX
ADD AX,OFFSET ADDRLIST
MOV SI,AX
POP BX
MOV WORD PTR [SI],BX ;STORE ADDR IN LIST
MOV AH,FIND_NEXT
INT DOS ;FIND NEXT FILE
JNC FOUND1 ;LOOP UNTIL NO MORE
LASTFILE:
RET
FIND_FILES ENDP
;********************************************************
; SORT POINTERS IN ADDRLIST, USING SHELL SORT ALGORITHM *
;********************************************************
SORT_FILES PROC NEAR
CMP BYTE PTR NFLAG,0 ;CHECK N FLAG
JNE NODUPES ;IF NO SORTING
MOV AX,WORD PTR NUMFILES
SORT1: ;TOP OF LOOP 1
SHR AX,1
MOV WORD PTR GAP,AX
JNZ SORT11 ;DONE IF GAP = 0
;***********************************************************
; make one more pass to eliminate duplicate file names *
; (necessary if user types something like "LS *.ASM H*.*") *
;***********************************************************
NODUPES:
MOV AX,WORD PTR NUMFILES
CMP AX,2
JGE NODUPES0
RET
NODUPES0:
MOV CX,1
NODUPES1:
MOV AX,WORD PTR NDUPES
AND AX,AX
JZ NODUPES2
ADD AX,CX
MOV SI,AX
ADD SI,SI
ADD SI,OFFSET ADDRLIST
MOV DI,CX
ADD DI,DI
ADD DI,OFFSET ADDRLIST
MOV AX,WORD PTR [SI]
MOV WORD PTR [DI],AX
NODUPES2:
MOV DX,CX
INC DX
ADD DX,WORD PTR NDUPES
CALL COMPARE
JNE NODUPES3
INC WORD PTR NDUPES ;BUMP # OF DUPLICATES
NODUPES3:
INC CX
MOV AX,WORD PTR NUMFILES
CMP CX,AX
JL NODUPES1
MOV AX,WORD PTR NUMFILES
SUB AX,WORD PTR NDUPES
MOV WORD PTR NUMFILES,AX
RET
SORT11:
INC AX
MOV BX,AX ;BX = COUNTER FOR LOOP 2
SORT2: CMP BX,WORD PTR NUMFILES ;TOP OF LOOP 2
JG SHORT SORT5
MOV CX,BX
SORT3: ;TOP OF LOOP 3
MOV DX,CX
SUB CX,WORD PTR GAP
JBE SHORT SORT4
CMP BYTE PTR TFLAG,0
JE SORT3A ;IF SORTING NAMES
CALL COMPDATE ;SORTING DATES, USE SPECIAL COMPARE
JMP SHORT SORT3B
CALL SWAP
JMP SORT3
SORT3A:
CALL COMPARE ;COMPARE ADDRLIST[DX], ADDRLIST[CX]
SORT3B:
MOV AX,0
JLE SORT3C
NOT AX
SORT3C:
CMP BYTE PTR RFLAG,0 ;R FLAG SET?
JE SORT3D ;NO
NOT AX ;YES, NEGATE RESULT OF COMPARISON
SORT3D:
AND AX,AX
JZ SORT4
CALL SWAP ;OUT OF ORDER, SO SWAP
JMP SORT3 ;BOTTOM OF LOOP 3
SORT4:
INC BX
JMP SORT2 ;BOTTOM OF LOOP 2
SORT5:
MOV AX,WORD PTR GAP
JMP SORT1 ;BOTTOM OF LOOP 1
SORT_FILES ENDP
;********************************************************
; COMPARE TWO FILE NAMES *
; ENTRY: CX AND DX ARE INDEX TO POINTERS (1..NUMFILES) *
; IN ADDRLIST *
;********************************************************
COMPARE PROC NEAR
PUSH CX
MOV SI,CX
ADD SI,SI
ADD SI,OFFSET ADDRLIST
MOV AX,WORD PTR [SI]
ADD AX,9
MOV SI,AX
MOV DI,DX
ADD DI,DI
ADD DI,OFFSET ADDRLIST
MOV AX,WORD PTR [DI]
ADD AX,9
MOV DI,AX
MOV CX,11
COMP_STRINGS
POP CX
RET
COMPARE ENDP
;*********************************************************
; COMPARE TWO FILES BY DATE *
; ENTRY: CX AND DX ARE INDEX TO POINTERS (1..NUMFILES) *
; IN ADDRLIST *
;*********************************************************
COMPDATE PROC NEAR
PUSH CX
MOV SI,CX
ADD SI,SI
ADD SI,OFFSET ADDRLIST
MOV AX,WORD PTR [SI]
MOV SI,AX
MOV DI,DX
ADD DI,DI
ADD DI,OFFSET ADDRLIST
MOV AX,WORD PTR [DI]
MOV DI,AX
MOV AX,WORD PTR [DI+3]
CMP AX,WORD PTR [SI+3]
JNE COMPD1 ;J/IF DATES NOT =
MOV AX,WORD PTR [DI+1] ;COMPARE TIMES
CMP AX,WORD PTR [SI+1]
COMPD1:
POP CX
RET
COMPDATE ENDP
;*********************************************************
; SWAP TWO OUT-OF-ORDER FILES *
; ENTRY: CX AND DX ARE INDEX TO POINTERS (1..NUMFILES) *
; IN ADDRLIST *
;*********************************************************
SWAP PROC NEAR
PUSH BX
MOV SI,CX
ADD SI,SI
ADD SI,OFFSET ADDRLIST
MOV BX,WORD PTR [SI]
MOV DI,DX
ADD DI,DI
ADD DI,OFFSET ADDRLIST
MOV AX,WORD PTR [DI]
MOV WORD PTR [SI],AX
MOV WORD PTR [DI],BX
POP BX
RET
SWAP ENDP
;********************
; DISPLAY DIRECTORY *
;********************
SHOW_FILES PROC NEAR
MOV SI,OFFSET ADDRLIST
MOV WORD PTR FIRSTSCREEN,0
MOV AL,BYTE PTR LFLAG
OR AL,BYTE PTR SFLAG ;S OR L FLAG SET?
JZ DISP0A ;NO
INC WORD PTR FIRSTSCREEN ;YES, SET FLAG
DISP0A:
CMP BYTE PTR ONEFLAG,0
JE DISP0 ;IF -1 FLAG NOT SET
MOV AX,WORD PTR NUMFILES ;NUMBER OF FILES THERE ARE
MOV WORD PTR MAXFILE,AX ;=LAST FILE # TO DISPLAY
MOV BX,2 ;INDEX TO 1ST FILE
JMP DISP11 ;GO SHOW FILES IN 1 COLUMN
DISP0:
MOV BYTE PTR MAXCOL,2 ;INITIALIZE MAXCOL FOR LONG DISPLAY
CMP BYTE PTR LFLAG,0 ;LONG DISPLAY FLAG SET?
JNE DISP2 ;YES, KEEP MAXCOL INTACT
CMP BYTE PTR SFLAG,0 ;S FLAG SET?
JE DISP1 ;NO
MOV BYTE PTR MAXCOL,NCOLUMNS ;YES, SET MAXCOL APPROPRIATELY
JMP SHORT DISP2
DISP1: MOV BYTE PTR MAXCOL,NCOLUMN ;SET NCOLUMN FOR SHORT DISPLAY, NO SIZES
DISP2:
MOV BL,BYTE PTR MAXCOL
MOV AL,MAXLINES
SUB AL,BYTE PTR FIRSTSCREEN
MUL BL ;COMPUTE (MAXLINES)*MAXCOL
MOV WORD PTR FILESPERSCREEN,AX ; SAVE RESULT
ADD AX,WORD PTR BASE ;ADD BASE TO GET LAST FILE # WE
;CAN SHOW ON THIS SCREEN
MOV BX,AX
MOV AX,WORD PTR NUMFILES ;COMPARE WITH TOTAL # FILES
INC AX ;+1
CMP AX,BX ;WILL ALL FILES FIT ON SCREEN?
JG DISP6 ;NO
MOV AX,WORD PTR NUMFILES ;GET MAX. FILE NUMBER
SUB AX,WORD PTR BASE ;FIND HOW MANY FILES TO GO
INC AX
DIV BYTE PTR MAXCOL ;COMPUTE # OF LINES/COLUMN
CMP AH,0 ;IS REMAINDER 0?
JE DISP5 ;YES, SKIP AHEAD
INC AL ;NO, ADD 1 TO LINE COUNT
DISP5: MOV AH,0 ;ZERO HI BYTE OF LINES/COLUMN
MOV WORD PTR MAXLINE,AX ;MAXLINE=# OF LINES TO SHOW IN
;THIS SCREEN
MOV AX,WORD PTR NUMFILES ;NUMBER OF FILES THERE ARE
MOV WORD PTR MAXFILE,AX ;=LAST FILE # TO DISPLAY
JMP SHORT DISP7
DISP6: MOV AX,MAXLINES ;TOO MANY FILES FOR 1 SCREEN, SO
SUB AX,WORD PTR FIRSTSCREEN
MOV WORD PTR MAXLINE,AX ;USE WHOLE SCREEN FOR DISPLAY
MOV AX,WORD PTR FILESPERSCREEN ; GET MAX. FILES/SCREEN
MOV WORD PTR MAXFILE,AX ;STORE AS # OF FILES TO SHOW
DISP7:
MOV WORD PTR COLCOUNT,1 ;START AT COLUMN 1
MOV WORD PTR LINECOUNT,1 ;AND LINE 1
MOV WORD PTR FILECOUNT,0 ;# OF FILES DISPLAYED IN THIS SCREEN
DISP8:
MOV CX,1 ;CX WILL COUNT UP TO COLCOUNT
MOV BX,0 ;BX WILL HOLD (CX-1)*MAXLINE
DISP9: ;COMPUTE (COLCOUNT-1)*MAXLINE
CMP CX,WORD PTR COLCOUNT
JGE DISP10
ADD BX,WORD PTR MAXLINE
INC CX
JMP DISP9
DISP10:
ADD BX,WORD PTR LINECOUNT ;ADD LINE COUNT
DEC BX ;-1
ADD BX,WORD PTR BASE ;ADD TO BASE
CMP BX,WORD PTR NUMFILES ;BLANK SLOT IN LAST COLUMN?
JG DISP12 ;YUP.
ADD BX,BX ;DOUBLE BX TO GET INDEX TO ADDRLIST
CMP WORD PTR COLCOUNT,1 ;1ST COLUMN?
JE DISP11 ;YES, NO FENCE
CALL DOFENCE ;SHOW FENCE
DISP11:
MOV DI,WORD PTR [SI+BX] ;GET ADDRESS OF FILE INFO
PUSH BX
CALL SHOW ;SHOW A FILE
CALL BUMPCOL ;UPDATE LINE & COLUMN COUNTS
POP BX
INC WORD PTR FILECOUNT ;BUMP FILE COUNT
MOV AX,WORD PTR FILECOUNT ;GET IT
CMP AX,WORD PTR MAXFILE ;DONE ALL FILES?
JGE DISP14 ;IF DONE
CMP BYTE PTR ONEFLAG,0 ;TEST 1-COLUMN FLAG
JE DISP13 ;IF NOT SET, DO PAGING
CALL CRLF ;SHOW CR/LF
ADD BX,2 ;ADVANCE TO NEXT SLOT IN ADDRLIST
JMP DISP11 ;DO NEXT FILE
DISP12:
CALL BUMPCOL
DISP13:
MOV AX,WORD PTR LINECOUNT ;GET LINE COUNT
CMP AX,WORD PTR MAXLINE ;IS IT >MAX LINE?
JLE DISP8 ;IF NOT
; COME HERE WHEN SCREEN IS FULL OR ALL FILES DONE:
DISP14:
CMP BYTE PTR ONEFLAG,0
JE DISP15 ;IF NOT -1
RET ;DONE IF -1
DISP15:
CMP WORD PTR COLCOUNT,1 ;IS COLUMN COUNT =1?
JE DISP16 ;YES, NO CR NEEDED
CMP WORD PTR NUMFILES,0 ;WAS AT LEAST ONE FILE DISPLAYED?
JE DISP16 ;NO, NO CR NEEDED
CALL CRLF ;SHOW CR AFTER LAST LINE
DISP16:
MOV AX,WORD PTR BASE
ADD AX,WORD PTR MAXFILE
MOV WORD PTR BASE,AX ;GET BASE FOR NEXT SCREEN
MOV BX,AX
MOV AX,WORD PTR NUMFILES
SUB AX,BX ;COMPUTE # FILES REMAINING
JBE DISP17 ;IF NO MORE
CALL WAITCR ;WAIT FOR USER
MOV WORD PTR FIRSTSCREEN,0 ;CLEAR "FIRST SCREEN" FLAG
JMP DISP2 ;DO NEXT SCREEN
DISP17:
RET
SHOW_FILES ENDP
BUMPCOL PROC NEAR
CMP BYTE PTR ONEFLAG,0
JNE BC1 ;JUST RETURN IF 1 COLUMN
INC WORD PTR COLCOUNT ;BUMP COLUMN COUNT
MOV AX,WORD PTR COLCOUNT
CMP AL,BYTE PTR MAXCOL ;PAST LAST COLUMN?
JLE BC1 ;NO, KEEP GOING
CALL CRLF ;YES, START NEW LINE
MOV WORD PTR COLCOUNT,1 ;RESET COLUMN COUNTER
INC WORD PTR LINECOUNT ;UPDATE LINE COUNTER
BC1:
RET
BUMPCOL ENDP
DOFENCE PROC NEAR ;SHOW "FENCE" BETWEEN COLUMNS
CMP BYTE PTR LFLAG,0 ;L FLAG SET?
JE SHORTFENCE ;NO.
CALL TWOSP
MOV AX,FENCE
CALL COUT
TWOSP:
MOV AL,SPACE ;YES, LONGER GAP BTWN. COLUMNS
CALL COUT
MOV AL,SPACE
CALL COUT
RET
SHORTFENCE:
MOV AX,SPACE
CALL COUT
MOV AX,FENCE
CALL COUT
MOV AX,SPACE
CALL COUT
RET
DOFENCE ENDP
;*******************************************
; SHOW FILE NAME, SIZE (DI POINTS TO INFO) *
;*******************************************
SHOW PROC NEAR
PUSH DI
MOV CX,8
SHOWNAME: ;SHOW FILE NAME
MOV AL,BYTE PTR [DI+9] ;GET CHAR.
CMP AL,'.'
JE SHOW1 ;DOT MEANS END OF NAME
CMP AL,0
JE SHOW1 ;SO DOES NULL
IF LOWCASE
CALL LC ;MAKE LOWER CASE
ENDIF
CALL COUT ;SHOW CHAR.
INC DI ;BUMP POINTER
DEC CX
JMP SHOWNAME ;LOOP
SHOW1:
IF PAD
PUSH AX ;FOUND END OF NAME, UNUSED COUNT IN CX
CALL SPOUT ;WRITE CX SPACES
POP AX
ENDIF
CMP AL,'.' ;WAS LAST CHAR DOT?
JNE NODOT ;NO
INC DI ;POINT PAST DOT
MOV AX,'.'
CALL COUT ;NOW WRITE DOT
JMP SHORT SHOW3
NODOT: MOV AX,SPACE ;SHOW SPACE (INSTEAD OF DOT)
CALL COUT
SHOW3:
PUSH CX
MOV CX,3 ;PREPARE TO SHOW EXTENSION (3 CHARS.)
SHOW4: MOV AL,BYTE PTR [DI+9] ;GET CHAR.
CMP AL,0
JE SHOW4A ;IF NULL, SHOW A SPACE
IF LOWCASE
CALL LC ;MAKE LOWER CASE
ENDIF
INC DI ;BUMP POINTER
JMP SHORT SHOW4B
SHOW4A: MOV AX,SPACE
SHOW4B:
CALL COUT ;SHOW CHAR.
LOOP SHOW4 ;LOOP
POP CX
SHOW5:
CALL SPOUT ;PAD OUT FIELD
SHOW6: POP DI ;POINT TO START OF INFO AGAIN
MOV AL,BYTE PTR [DI] ;GET FILE ATTRIBUTE
AND AL,00010000B ;IS IT A DIRECTORY?
JZ SHOW7 ;NO.
CMP BYTE PTR LFLAG,0 ;LONG DISPLAY?
JE SHOW6B ;NO
MOV CX,3 ;YES, 3 EXTRA SPACES
CALL SPOUT
SHOW6B: ;HAVE DIRECTORY
CMP BYTE PTR SFLAG,0
JNE SHOW6C ;IF S FLAG SET
CMP BYTE PTR LFLAG,0
JNE SHOW6C ;IF L FLAG SET
RET ;OTHERWISE JUST RETURN
SHOW6C:
MOV DX,OFFSET TXT0
CALL PRTSTR ;PRINT <DIR>
CMP BYTE PTR LFLAG,0 ;IS L FLAG SET?
JNE SHOW8A ;YES, FINISH UP
RET ;NO, ALL DONE
SHOW7: ;HAVE FILE, NOT DIR
CMP BYTE PTR LFLAG,0 ;L FLAG SET?
JNE SHOW8 ;YES, LONG DISPLAY
CMP BYTE PTR SFLAG,0 ;S FLAG SET?
JE SHOW9 ;NO, SUPPRESS FILE SIZE DISPLAY
MOV AX,WORD PTR [DI+5] ;SHORT DISPLAY, GET LSW FILE SIZE
MOV DX,WORD PTR [DI+7] ;AND MSW FILE SIZE
CALL MAKEK ;CONVERT TO KBYTES
MOV AL,SPACE ;WITH LEADING SPACES,
MOV CX,5 ;AND FIELD WIDTH = 5,
CALL DECOUT ;SHOW FILE SIZE
SHOW9:
RET ;DONE
SHOW8: MOV AX,WORD PTR [DI+5] ;LONG DISPLAY
PUSH SI ;MOVE SIZE TO DI:SI
MOV SI,AX
MOV AX,WORD PTR [DI+7]
PUSH DI
MOV DI,AX
MOV AL,SPACE ;WITH LEADING SPACES,
CALL PRINTDD ;SHOW FILE SIZE IN BYTES
POP DI
POP SI
SHOW8A:
MOV CX,2
CALL SPOUT ;PRINT 2 SPACES
MOV AX,WORD PTR [DI+3] ;GET PACKED DATE
CALL PRTDTE ;SHOW IT
MOV CX,2
CALL SPOUT ;PRINT 2 SPACES
MOV AX,WORD PTR [DI+1] ;GET PACKED TIME
CALL PRTTME ;SHOW IT
RET ;DONE
SHOW ENDP
IF LOWCASE
;************************************
; CONVERT CHAR. IN AL TO LOWER CASE *
;************************************
LC PROC NEAR
CMP AL,'A'
JL NOTUC
CMP AL,'Z'
JG NOTUC
ADD AL,'a'-'A'
NOTUC:
RET
LC ENDP
ENDIF
;*******************************************
; SUBROUTINE - WRITES CX SPACES TO SCREEN *
;*******************************************
SPOUT PROC NEAR
JCXZ SPOUT1
MOV AL,SPACE
CALL COUT
DEC CX
JMP SPOUT
SPOUT1: RET
SPOUT ENDP
;****************************************
; SUBROUTINE - PAUSES AT END OF SCREEN *
;****************************************
WAITCR PROC NEAR
CMP BYTE PTR ISDEV,0 ;ARE WE WRITING TO A DEVICE?
JE FILEOUT ;NO
MOV DX,OFFSET MSG3
CALL ERRORMSG ;PROMPT USER FOR OK TO SHOW NEXT SCREEN
CALL CLRCO ;CLEAR TYPE-AHEAD
CALL CIN ;GET A CHAR.
CALL CLRSCR ;CLEAR SCREEN
RET
FILEOUT:
CALL CRLF ;FILE OUTPUT, JUST SHOW CR/LF TO SEPARATE SCREENS
RET
WAITCR ENDP
;********************************************
; ROUTINE TO CLEAR SCREEN, HOME CURSOR: *
; (MAY HAVE TO CHANGE FOR NON-IBM MACHINES) *
;********************************************
CLRSCR PROC NEAR
PUSH BX
IF IBM
MOV DX,0
CALL MOVEXY ;MOVE TO HOME POSITION
MOV AL,BYTE PTR VMODE ;GET CURRENT VIDEO MODE
MOV AH,0
INT BIOS ;RESET MODE (CLEARS SCREEN)
ELSE
MOV AL,FF ;NON-IBM CLEAR SCREEN
CALL COUT ;USE FF (WILL WORK ON MOST TERMINALS)
ENDIF
POP BX
RET
CLRSCR ENDP
;*****************************************
; CURSOR POSITIONING ROUTINE (USES BIOS) *
;*****************************************
MOVEXY PROC NEAR ;MOVE TO ROW (DH) AND COLUMN (DL)
MOV AH,2
MOV BH,BYTE PTR VPAGE ;VIDEO PAGE #
MOV BL,0 ;COLOR (DON'T CHANGE)
INT BIOS ;MOVE CURSOR
RET
MOVEXY ENDP
;**************************************************
; DISPLAY NUMBER OF FILES, SPACE USED, SPACE FREE *
;**************************************************
SHOW_INFO PROC NEAR
MOV AL,BYTE PTR SFLAG
OR AL,BYTE PTR LFLAG ;S OR L FLAG SET?
JNE INFO0A ;YES, GO AHEAD
RET ;NO, SUPPRESS DISPLAY
INFO0A:
MOV BX,WORD PTR NUMFILES ;GET NUMBER OF FILES
OR BX,BX ;> 0?
JNE INFO0B ;YES, GO AHEAD
RET
INFO0B:
MOV AL,0 ;SUPPRESS LEADING 0'S
MOV CX,5 ;FIELD WIDTH = 5
CALL DECOUT ;SHOW # FILES
MOV DX,OFFSET TXT1
CALL PRTSTR
CMP BYTE PTR LFLAG,0 ;L FLAG SET?
JE INFO1 ;NO, SHORT DISPLAY
MOV DI,WORD PTR USED+2
MOV SI,WORD PTR USED ;GET SPACE USED IN SI:DI
MOV AL,0 ;SUPPRESS LEADING 0'S
CALL PRINTDD ;SHOW SPACE USED
MOV DX,OFFSET TXT2
CALL PRTSTR
JMP SHORT INFO2
INFO1: ;SHORT DISPLAY
MOV AX,WORD PTR USED
MOV DX,WORD PTR USED+2 ;GET AMT. USED IN DX:AX
CALL MAKEK ;CONVERT TO K
MOV AL,0 ;SUPPRESS LEADING 0'S
MOV CX,5 ;FIELD WIDTH = 5
CALL DECOUT ;SHOW AMT. USED
IF LOWCASE
MOV AL,'k'
ELSE
MOV AL,'K'
ENDIF
CALL COUT ;SHOW LETTER K
INFO2:
MOV AH,CURRENT_DISK
INT DOS ;GET CURRENT DISK
PUSH AX ;SAVE IT
MOV DL,BYTE PTR DRIVE ;DL = DRIVE WE SPECIFIED
CMP DL,0 ;CURRENT DISK?
JE NOCHANGE ;YES, NO NEED TO CHANGE
INC AL
CMP AL,DL ;SAME AS CURRENT DISK?
JE NOCHANGE ;YES, NO NEED TO CHANGE
DEC DL ;MAKE 0=A, ETC.
MOV AH,SELECT_DISK
INT DOS ;SELECT DISK
NOCHANGE:
MOV DL,0 ;NOW USING CURRENT DISK,
MOV AH,GET_FREE_SPACE
INT DOS ;GET FREE SPACE
MUL BX ;COMPUTE # SECTORS FREE
PUSH DX ;SAVE HI WORD
MUL CX ;MULTIPLY LO WORD OF SECTOR COUNT
;BY BYTES/SECTOR
MOV WORD PTR LOSIZE,AX ;SAVE LO WORD OF FREE SPACE
POP BX ;GET HI WORD OF SECTOR COUNT
PUSH DX ;SAVE CARRY FROM LO WORD MULT.
MOV AX,BX ;MULTIPLICAND IN AX
MUL CX ;MULTIPLY HI WORD OF SECTOR COUNT
;TIMES BYTES/SECTOR
POP BX ;GET CARRY FROM LO WORD
ADD AX,BX ;ADD IT
MOV DX,AX ;DX = HI WORD OF FREE SPACE
MOV AX,WORD PTR LOSIZE ;AX = LO WORD OF FREE SPACE
CMP BYTE PTR LFLAG,0 ;L FLAG SET?
JE INFO3 ;NO, SHORT DISPLAY
MOV DI,DX ;LONG DISPLAY,
MOV SI,AX ;MOVE AMT. FREE TO DI:SI
MOV AL,0 ;SUPPRESS LEADING 0'S
CALL PRINTDD ;SHOW AMT. FREE
MOV DX,OFFSET TXT3
CALL PRTSTR
JMP SHORT INFO4
INFO3: ;SHORT DISPLAY
CMP DX, K
JGE BIG_DISK ;IF >65 MEGABYTES
MOV CX,K ;CX = 1 K
DIV CX ;DIVIDE TO GET KBYTES FREE
MOV DX, 0
JMP SHORT INFO3A
BIG_DISK:
MOV CX, 10*K
DIV CX ;DIVIDE BY 10K
MOV BX,10
MUL BX ;GET KBYTES FREE IN DX:AX
INFO3A:
PUSH AX ;SAVE LO WORD OF SPACE FREE
MOV AL,SPACE
CALL COUT ;WRITE SPACE
MOV AL,'('
CALL COUT ;WRITE PAREN
POP SI ;RESTORE LO WORD OF SPACE FREE
MOV DI,DX ;LONG DISPLAY,
MOV AL,0 ;SUPPRESS LEADING 0'S
CALL PRINTDD ;SHOW AMT. FREE
IF LOWCASE
MOV AL,'k'
ELSE
MOV AL,'K'
ENDIF
CALL COUT
MOV DX,OFFSET TXT4
CALL PRTSTR
INFO4:
CALL CRLF ;SHOW CR/LF
POP DX
MOV AH,SELECT_DISK ;RESET DEFAULT DISK
INT DOS
RET ;DONE
SHOW_INFO ENDP
;***************************************************
; MAKEK = TAKE QUAD # IN DX:AX, CONVERT TO K IN BX *
;***************************************************
MAKEK PROC NEAR
MOV BX,K
DIV BX ;DIVIDE TO GET SIZE IN K
MOV BX,AX ;QUOTIENT IN BX
CMP DX,0 ;MODULUS>0?
JE NOROUND
INC BX ;IF SO, ROUND UP
NOROUND:
RET
MAKEK ENDP
; The following two routines are adapted from SDIR Version
; 2.4, by Ted Reuss (modified from a program by John Chapman), on
; PC-SIG Volume 185.
SUBTTL PRINT DATE, TIME & # FILES ROUTINES
PAGE
; PC-DOS packed date <yyyyyyym mmmddddd>
P_DTE RECORD P_YR:7,P_MO:4,P_DY:5
; PC-DOS packed time <hhhhhmmm mmmsssss>
P_TME RECORD P_HR:5,P_MI:6,P_2S:5
PRTDTE PROC NEAR ;Print packed date in AX as MM/DD/YY
OR AX,AX
JNZ K1 ;If date <> 0
MOV CX,8
CALL SPOUT ;Print 8 spaces
RET
K1: PUSH AX
AND AX,MASK P_MO ;Mask the month,
MOV CL,P_MO ; set shift count,
SHR AX,CL ; right justify, &
CALL PRTBCD ; print it.
MOV AX,'/'
CALL COUT
POP AX
PUSH AX
AND AX,MASK P_DY ;Mask the day &
CALL PRTBCD ; print it.
MOV AX,'/'
CALL COUT
POP AX
AND AX,MASK P_YR ;Mask the year,
MOV CL,P_YR ; set shift count,
SHR AX,CL ; right justify,
ADD AX,80 ; add in year bias, &
; print it.
PRTBCD: AAM ;Convert AL to BCD
OR AX,'00' ;Convert to ASCII
PUSH AX
MOV AL,AH
CALL COUT ;High order digit
POP AX
CALL COUT ;Low order digit
RET
PRTDTE ENDP
PRTTME PROC NEAR ;Print packed time in AX as HH:MM
OR AX,AX
JNZ L1 ;if date<>0
MOV CX,5
CALL SPOUT ;Print 5 spaces
RET
L1: PUSH AX
AND AX,MASK P_HR ;Mask the hours,
MOV CL,P_HR ; set shift count,
SHR AX,CL ; right justify, &
CALL PRTBCD ; print it.
MOV AX,':'
CALL COUT
POP AX
AND AX,MASK P_MI ;Mask the minutes,
MOV CL,P_MI ; set shift count,
SHR AX,CL ; right justify, &
CALL PRTBCD ; print it.
RET
PRTTME ENDP
CODE ENDS
END ENTRY